package server;

import java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.Collections;

/**
 * Klasa glowna serwera
 * @version 1.0
 * @author Mateusz Domagala
 */
public class ServerBadugi 
{
	/** zmienne klasowe */
   ServerSocket server;
   int port, numberOfPlayers, numberOfChips, smallBlind, bigBlind;
   Game game;
   Thread gameThread;
   /* wolne identyfikatory dla graczy. potrzebne w przypadku wychodzenia gracza i wejscia nowego gracza */
   public ArrayList<Integer> availableID;
   
   /*
    * Lista podlaczonych graczy. Maksymalna liczba graczy to: numberOfPlayers
    * 
    * */
   ArrayList<ClientService> connectedPlayers = new ArrayList<ClientService>(); // sockety do obslugiwania graczy
   
   /**
    * Konstruktor
    * @param port nr portu na którym serwer będzie nasłuchiwać
    * @param  
    * @throws Exception 
    */
   
   public ServerBadugi(int port, int numberOfPlayers, int numberOfChips, int smallBlind, int bigBlind) throws Exception
   {
   	if (port < 0 || port > 65535) throw new Exception("Nr portu musi byc w przdziale [1,65535]");
      if (numberOfPlayers < 2 || numberOfPlayers > 6) throw new Exception("Liczba uczestnikow musi byc w przedziale [2,6]");
      this.port = port;
      this.numberOfPlayers = numberOfPlayers;
      this.numberOfChips = numberOfChips;
      this.smallBlind = smallBlind;
      this.bigBlind = bigBlind;
      /* watek gry */
      this.game = new Game(this);
      this.availableID = new ArrayList<Integer>();
      
      /* iniclaizacja tablicy z wolnymi numerami graczy */
      for(int i=1; i<=numberOfPlayers; i++)
      	availableID.add(i);
      
   }
   
   synchronized public int getFreeID() // patrzymy czy tablica > 0 - jesli tak to przydzielamy id
   {
   	int id = 0;
   	if (availableID.size()>0)
   	{
   		id = availableID.get(0); // najblizszy z brzegu, usuwamy 
   		availableID.remove(0);
   	}
   	return id;
   }
   
   synchronized public boolean returnFreeID(int id) 
   {
   	if (availableID.contains(id)) return false; // jesli oddaje wolny nr to blad
  		availableID.add(id); // oddaje do tablicy wolnych
  		Collections.sort(availableID); // sortujemy 
  		return true;
   }
   
   /**
    * uruchomienie serwera 
    */
   public void go()
   {
      try
      {
			/** rozpoczecie nasluchiwania polaczen klientow na porcie "port" */
         server = new ServerSocket(port);
      } 
      catch (IOException e)
      {
         System.out.println("Blad inicjalizacji portu: [" + port + "] ");
         System.exit(-1);
      }
      
		System.out.println("Oczekiwanie na polaczenia na porcie: [" + port + "] ");
		
		/* uruchomienie watku z gra */
		gameThread = new Thread(game);
		game.setThread(gameThread);
		gameThread.start();
		
      while(true)
      {
         ClientService w; // zmienna typu ClientService do obslugi
         try
         {
				/** oczekiwanie na połączenie nowego klienta (server.accept) */
            w = new ClientService(server.accept(), this);
				/** połączenie przyszło, to utworzenie nowego wątku dla obslugi klienta */
            Thread t = new Thread(w);
				/** wystartowanie nowego wątku z obsługą klienta */
            t.start();
         } 
         catch (IOException e) 
         {
            System.out.println("Blad przy probie polaczenia klienta: ");
            System.exit(-1);
         }
      }
   }
   
   /**
    * Funkcja uruchamiana przy zakończeniu pracy aplikacji. Wywoływana gdy obiekt ServerBadugi nie jest już potrzebny 
    */
   protected void finalize() throws Throwable
   {
      try
      {
			/** zamkniecie gniazda nasluchujacego */
         server.close();
      }
      catch(IOException e)
      {
         System.out.println("Blad przy probie zamkniecia socketu");
         System.exit(-1);
      }
      finally
      {
         super.finalize(); 
      }
   }
   
    /**
	  * Glowna funkcja aplikacji
     * @param args parametry przekazane w linii komend
     */
   public static void main(String[] args) 
   {
		/** sprawdzenie liczby parametrow */
      if (args.length < 5)
      {
         System.out.println("Brak parametrow uruchomienia serwera. Prawidlowe uruchomienie: java ServerBadugi <nr portu> <liczba uczestnikow> <liczba zetonow> <small blind> <big blind>");
         System.exit(-1);
      }
      int p,lu, lz, sb, bb;
      ServerBadugi ss;
      try
      {
			/** zamiana parametroww na liczby calkowite */
         p  = Integer.parseInt(args[0]);
         lu = Integer.parseInt(args[1]);
         lz = Integer.parseInt(args[2]);
         sb = Integer.parseInt(args[3]);
         bb = Integer.parseInt(args[4]);
			
         /** utworzenie obiektu serwera */
         ss = new ServerBadugi(p, lu, lz, sb, bb);
			/** wystartowanie serwera */
         ss.go();
      }
      catch(Exception e) // zle parametry
      {
         System.out.println(e.getMessage());
         System.exit(-1);
      }
   }
}
